package com.demo.util;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.util.FileUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.HorizontalAlignment;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;





/**
 * easyexcel工具类
 *
 * @Description
 * @Autoher wanglingbin
 * @Date 2020-04-03 16:09
 **/
public class EasyExcelUtils {

    /**
     * 读取数据
     *
     * @param fileName
     * @param clazz
     * @param listener
     * @param <T>
     */
    public static <T> void readExcelOnce(String fileName, Class<T> clazz, AnalysisEventListener listener) {
        EasyExcel.read(fileName, clazz, listener).sheet().doRead();
    }

    /**
     * 输入流的读取
     *
     * @param inputStream
     * @param clazz
     * @param listener
     * @param <T>
     */
    public static <T> void readExcelOnce(InputStream inputStream, Class<T> clazz, AnalysisEventListener listener) {
        EasyExcel.read(inputStream, clazz, listener).sheet().doRead();
    }


    /**
     * 读取多个sheet的数据
     *
     * @param fileName
     * @param clazz
     * @param listener
     * @param sheetNames
     * @param <T>
     */
    public static <T> void readExcelRepeated(String fileName, Class<T> clazz, AnalysisEventListener listener, String... sheetNames) {
        ExcelReader excelReader = EasyExcel.read(fileName).build();
        List<ReadSheet> readSheets = Lists.newArrayList();
        for (String sheetName : sheetNames) {
            ReadSheet readSheet = EasyExcel.readSheet(sheetName).head(clazz).registerReadListener(listener).build();
            readSheets.add(readSheet);
        }
        excelReader.read(readSheets);
    }

    /**
     * 一次性写入excel
     *
     * @param fileName
     * @param sheetName
     * @param clazz
     */
    public static <T> void writeExcelOnce(String fileName, String sheetName, Class<T> clazz, List<T> data) {
        // 获取单元格样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = getDefalutHorizontalCellStyleStrategy();
        // 写数据
        EasyExcel.write(fileName, clazz)
                .excelType(ExcelTypeEnum.XLSX)
                .sheet(sheetName)
                .registerWriteHandler(horizontalCellStyleStrategy)
                //最大长度自适应
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .doWrite(data);
    }

    /**
     * web对象的写
     *
     * @param outputStream
     * @param sheetName
     * @param clazz
     * @param data
     * @param <T>
     */
    public static <T> void writeExcelOnce(OutputStream outputStream, String sheetName, Class<T> clazz, List<T> data) {
        // 获取单元格样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = getDefalutHorizontalCellStyleStrategy();
        // 写数据
        EasyExcel.write(outputStream, clazz)
                .excelType(ExcelTypeEnum.XLSX)
                .sheet(sheetName)
                .registerWriteHandler(horizontalCellStyleStrategy)
                //最大长度自适应
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .doWrite(data);
    }

    /**
     * web对象的写:写动态表头
     * @param outputStream
     * @param sheetName
     * @param data
     * @param head
     * @param <T>
     */
    public static <T> void writeExcelOnce(OutputStream outputStream, String sheetName, List<T> data,List<List<String>> head) {
        // 获取单元格样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = getDefalutHorizontalCellStyleStrategy();
        // 写数据
        EasyExcel.write(outputStream)
                .head(head)
                .excelType(ExcelTypeEnum.XLSX)
                .sheet(sheetName)
                .registerWriteHandler(horizontalCellStyleStrategy)
                //最大长度自适应
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .doWrite(data);
    }

    /**
     * 构建输入流
     *
     * @param fileName
     * @param sheetName
     * @param clazz
     * @param data
     * @param <T>
     * @return
     * @throws FileNotFoundException
     */
    public static <T> InputStream buildExcelInputStream(String fileName, String sheetName, Class<T> clazz, List<T> data) throws FileNotFoundException {
        // 添加excel后缀
        if (StringUtils.lastIndexOf(fileName, ".") == -1) {
            fileName += ExcelTypeEnum.XLSX.getValue();
        }
        // 将文件写到临时目录下
        File tmpFile = FileUtils.createCacheTmpFile();
        File file = new File(tmpFile.getPath() + File.separator + fileName);
        // 通过easyexcel写入
        writeExcelOnce(new FileOutputStream(file), sheetName, clazz, data);
        // 返回输入流
        InputStream in = new FileInputStream(file);
        return in;
    }

    /**
     * 构建输入流:写动态表头
     * @param fileName
     * @param sheetName
     * @param data
     * @param head
     * @param <T>
     * @return
     * @throws FileNotFoundException
     */
    public static <T> InputStream buildExcelInputStream(String fileName, String sheetName, List<T> data,List<List<String>> head) throws FileNotFoundException {
        // 添加excel后缀
        if (StringUtils.lastIndexOf(fileName, ".") == -1) {
            fileName += ExcelTypeEnum.XLSX.getValue();
        }
        // 将文件写到临时目录下
        File tmpFile = FileUtils.createCacheTmpFile();
        File file = new File(tmpFile.getPath() + File.separator + fileName);
        // 通过easyexcel写入
        writeExcelOnce(new FileOutputStream(file), sheetName, data,head);
        // 返回输入流
        InputStream in = new FileInputStream(file);
        return in;
    }

    /**
     * 创建excelWriter
     *
     * @param fileName
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> ExcelWriter buildExcelWriter(String fileName, Class<T> clazz) {
        // 创建ExcelWriter
        ExcelWriter excelWriter = EasyExcel.write(fileName, clazz).excelType(ExcelTypeEnum.XLSX).build();
        return excelWriter;
    }

    /**
     * 创建excelWriter
     *
     * @param outputStream
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> ExcelWriter buildExcelWriter(OutputStream outputStream, Class<T> clazz) {
        // 创建ExcelWriter
        ExcelWriter excelWriter = EasyExcel.write(outputStream, clazz).excelType(ExcelTypeEnum.XLSX).build();
        return excelWriter;
    }


    /**
     * 创建writeSheet
     *
     * @param sheetName
     * @return
     */
    public static WriteSheet buildWriteSheet(String sheetName) {
        // 获取单元格样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = getDefalutHorizontalCellStyleStrategy();
        // 获取sheet
        WriteSheet writeSheet = EasyExcel.writerSheet(sheetName)
                .registerWriteHandler(horizontalCellStyleStrategy)
                //最大长度自适应
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .build();
        return writeSheet;
    }

    /**
     * 设置单元格样式
     *
     * @return
     */
    private static HorizontalCellStyleStrategy getDefalutHorizontalCellStyleStrategy() {
        // 头的策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //设置表头居中对齐
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        // 内容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //设置内容靠左对齐
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    }


    /**
     * 导出
     *
     * @param response
     * @param data
     * @param fileName
     * @param sheetName
     * @param clazz
     * @throws Exception
     */
    public static void writeExcel(HttpServletResponse response, List<? extends Object> data, String fileName, String sheetName, Class clazz) throws Exception {
        //表头样式
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //设置表头居中对齐
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        //内容样式
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //设置内容靠左对齐
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
        EasyExcel.write(getOutputStream(fileName, response), clazz).excelType(ExcelTypeEnum.XLSX).sheet(sheetName).registerWriteHandler(horizontalCellStyleStrategy).doWrite(data);

    }

    private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        return response.getOutputStream();
    }

}
